
/*
 * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
 *
 * (b)  If this Sample Code is distributed as part of the Display PostScript
 *	System Software Development Kit from Adobe Systems Incorporated,
 *	then this copy is designated as Development Software and its use is
 *	subject to the terms of the License Agreement attached to such Kit.
 *
 * (c)  If this Sample Code is distributed independently, then the following
 *	terms apply:
 *
 * (d)  This file may be freely copied and redistributed as long as:
 *	1) Parts (a), (d), (e) and (f) continue to be included in the file,
 *	2) If the file has been modified in any way, a notice of such
 *      modification is conspicuously indicated.
 *
 * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
 *	Adobe Systems Incorporated.
 * 
 * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
 *	CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
 *	AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
 *	ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
 *	OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
 *	WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
 *	WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
 *	DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
 *	FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
 *	OF THIRD PARTY RIGHTS.
 */

/*
 *	StrokeView.m
 *
 *	The purpose of the application is to show the difference when stroke adjustment is
 *	turned on and turned off.  The default state on the NeXT computer is ON.  Horizontal,
 *	verticle, diagonal  lines and arcs are drawn at a set linespacing.  The linewidth can be
 *	varied from the interface.
 *
 *	This file contains the methods for the StrokeView class, a subclass of view.
 *	The important item to note is simply the effect that stroke adjustment has.  Refer
 *	to the documentation for specifics on how stroke adjustment works.
 *
 *	Version:	2.0
 *	Author:	John-Henry Gross, Ken Fromm
 *	History:
 *			03-07-91		Added this comment.
 */

#import "StrokeView.h"
#import "StrokeViewWraps.h"
#import <appkit/Button.h>
#import <appkit/Control.h>
#import <appkit/Matrix.h>
#import <appkit/TextField.h>
#import <dpsclient/wraps.h>
#include <math.h>

@implementation StrokeView

/* Allocate a gstate and set clipping to NO.  The gstate is allocated because we do not
*  want to reset the individual drawing variables when the context is switched back to this
*  view.  Place the line [self setClipping:NO]; after allocating the gstate to see the effect
*  clipping has.
*
*  The PSWDefs() call sends some definitions used in the wraps to the interpreter.  They
*  will be available in the interpreter when the wraps call them. 
*/
+ newFrame:(NXRect *) frm
{
	self = [super newFrame:frm]; 
	[self allocateGState]; 
	
	PSWDefs ();

	return self;
}

/* Free the gstate upon quitting. */
- free
{
   	[self  freeGState];
    
   	return [super free];
}

- setTimeDisplay:anObject
{
	timeDisplay = anObject;
	return self;
}

- setFieldWidth:anObject
{
	fieldWidth = anObject;
	return self;
}

- setMatrixLineTypes:anObject
{
	matrixLineTypes = anObject;
	return self;
}

- setStrokeAdjustment:(BOOL)strokeAdjValue
{
	strokeAdjustment = strokeAdjValue;
	return self;
}

/********************************************************************************************
*	These static procedures are called within drawSelf:  They simply draw lines in
*	the rectangle passed in.   They have been separated out of drawSelf:: mainly 
*	for cosmetic reasons. 
********************************************************************************************/

/*  Adds horizontal lines to the path within rect. */
static void makeHorizLines(NXRect  *rect)
{
	float 	ypos, linespacing;
	
	linespacing = rect->size.height/NUMLINESHORIZ;
	for (ypos = rect->origin.y; ypos <= rect->origin.y + rect->size.height; ypos += linespacing)
		PSWMakeLine(rect->origin.x, ypos, rect->origin.x + rect->size.width, ypos);

	PSstroke();
}

/*  Adds verticle lines to the path within rect. */
static void makeVertLines(NXRect  *rect)
{
	float 	xpos, linespacing;
	
	linespacing = rect->size.width/NUMLINESVERT;
	for (xpos = rect->origin.x; xpos <= rect->origin .x + rect->size.width; xpos += linespacing)
		PSWMakeLine(xpos, rect->origin.y, xpos, rect->origin.y + rect->size.height);

	PSstroke();
}

/*  Adds diagonal lines to the path within rect.  The rectangle has to be clipped because
*  the length of the line exceeds the height and the width.  Clipping will show only the 
*  portion of the lines that fall within the rectangle.
 */
static void makeDiagLines(NXRect  *rect)
{
	float		angle, length;
	
	length = (float) sqrt(rect->size.width * rect->size.width + rect->size.height * rect->size.height);

	PSgsave();
		PStranslate(rect->origin.x, rect->origin.y);
	
		for (angle = 0; angle <= 90; angle += DIAGDEGS) 
		{
			PSWMakeLine(0, 0, length, 0);
			PSrotate(DIAGDEGS);
		}
		PSstroke();
	PSgrestore();
}


/*  Adds arcs within rect.  Clipping is necessary because height is greater than the width
*  and so some arcs will travel outside the rectangle
*/
static void makeArcs(NXRect  *rect)
{
	float 	radius, maxradius, spacing;
	
	maxradius = (float) sqrt(rect->size.width * rect->size.width +
						 rect->size.height * rect->size.height);
	spacing = maxradius/NUMARCS;
	for (radius = spacing; radius <= maxradius; radius += spacing)
			PSWMakeArc(rect->origin.x, rect->origin.y, radius, 0, 90);

	PSstroke();

}

/* Actions performed:  erase the display times in the interface, obtain the state of each
*  line type button, clear the view by drawing a new background, set the values of the drawing
*  variables, draw stroke adjusted lines and then non-stroke adjusted lines (displaying the
*  times as well), reset the stroke adjustment and then draw the borders around the view.
*/
- drawSelf:(NXRect *)r :(int) count
{
	int	ElapsedTime;

	[timeDisplay setStringValue:""];

	PSsetgray(BACKGROUND);
	PSrectfill(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);

	PSsetstrokeadjust(YES);
	PSsetlinewidth(BORDERWIDTH);
	PSsetgray(BORDERCOLOR);
	PSrectstroke(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
	
	PSsetgray(LINECOLOR);
	PSsetlinewidth([fieldWidth floatValue]);
	PSsetstrokeadjust(strokeAdjustment);
	
	PSWMarkTime(); NXPing ();	
		if ([[matrixLineTypes cellAt:0 :0] state])
			makeHorizLines(&bounds);		
		 if ([[matrixLineTypes cellAt:0 :1] state])
			makeVertLines(&bounds);		
		 if ([[matrixLineTypes cellAt:1 :0] state])
			makeDiagLines(&bounds);
		if ([[matrixLineTypes cellAt:1 :1] state])
			makeArcs(&bounds);
	PSWReturnTime (&ElapsedTime);

	[timeDisplay setIntValue:ElapsedTime];
				
	return self;
}


@end
